// Kony


#include "UI/WidgetController/SpellMenuWidgetController.h"

#include "GameplayTagContainer.h"
#include "AbilitySystem/BaseAbilitySystemComponent.h"
#include "AbilitySystem/Data/AbilityInfo.h"
#include "Player/BasePlayerState.h"

//广播初始化值 子类重写
void USpellMenuWidgetController::BroadcastInitializeValues()
{
	//父类调用 但暂时没调用所以注释掉
	// Super::BroadcastInitializeValues();
	//如果需要添加能力信息 需要进入下面的函数增加对应的Info存储
	BroadcastAbilityInfo();
	//获取法术点数,初始值
	SpellPointsChanged.Broadcast(GetBasePS()->GetSpellPoints());
}
//绑定回调函数到依赖项
void USpellMenuWidgetController::BindCallbacksToDependencies()
{
	// Super::BindCallbacksToDependencies();
	//绑定升级后能力状态更变广播
	GetBaseASC()->AbilityStatusChangedDelegate.AddLambda([this](const FGameplayTag& AbilityTag, const FGameplayTag& InputTag, const FGameplayTag& StatusTag, int32 AbilityLevel)
	{
		//判断如果当前选择的技能状态和状态改编后的技能是同一个 就设置状态
		if (SelectedAbility.AbilityTag.MatchesTagExact(AbilityTag))
		{
			SelectedAbility.StatusTag = StatusTag;
			//这部分广播选择的技能状态是解决 打开菜单时 升级 可以显示正确的按钮状态
			//是否禁用升级技能按钮
			bool bEnableSpendPoints = false;
			//是否禁用装备技能按钮
			bool bEnableEquip = false;
			//调用判断
			ShouldEnableButtons(StatusTag, CurrentSpellPoints, bEnableSpendPoints, bEnableEquip);
			//当前技能描述
			FString Description;
			//下一级技能描述
			FString NextLevelDescription;
			//调用获取能力描述
			GetBaseASC()->GetDescriptionsByAbilityTag(AbilityTag,Description,NextLevelDescription);
			//广播按钮状态
			SpellSelectedDelegate.Broadcast(bEnableSpendPoints, bEnableEquip,Description, NextLevelDescription);
		}
		if (AbilityInfo)
		{
			//获取能力信息，存储到传递变量中
			FBaseAbilityInfo Info = AbilityInfo->FindAbilityInfoForTag(AbilityTag);
			Info.StatusTag = StatusTag;
			Info.InputTag = InputTag;
			//广播到UI控件
			AbilityInfoDelegate.Broadcast(Info);
		}
	});
	//绑定技能拦装备技能广播
	GetBaseASC()->AbilityEquippedDelegate.AddUObject(this,&USpellMenuWidgetController::OnAbilityEquipped);
	//获取用户状态 读取等级相关数据
	GetBasePS()->OnSpellPointsChangedDelegate.AddLambda([this](int32 Points)
	{
		//广播法术点变更
		SpellPointsChanged.Broadcast(Points);
		CurrentSpellPoints = Points;

		//这部分广播选择的技能状态是解决 打开菜单时 升级 可以显示正确的按钮状态
		//是否禁用升级技能按钮
		bool bEnableSpendPoints = false;
		//是否禁用装备技能按钮
		bool bEnableEquip = false;
		//调用判断
		ShouldEnableButtons(SelectedAbility.StatusTag, CurrentSpellPoints, bEnableSpendPoints, bEnableEquip);
		//当前技能描述
		FString Description;
		//下一级技能描述
		FString NextLevelDescription;
		//调用获取能力描述
		GetBaseASC()->GetDescriptionsByAbilityTag(SelectedAbility.AbilityTag,Description,NextLevelDescription);
		//广播按钮状态
		SpellSelectedDelegate.Broadcast(bEnableSpendPoints, bEnableEquip,Description, NextLevelDescription);
	});
}
//用能力标签选择法术,判断当前法术是否可升级或可装备，并进行广播
void USpellMenuWidgetController::SpellSelected(const FGameplayTag& AbilityTag)
{
	if (bWaitingForEquipSelect)
	{
		//TODO：选择技能时 发送取消选择委托，这2行委托以后改成拖拽的可以去掉
		//能力类型
		const FGameplayTag SelectedAbilityType = AbilityInfo->FindAbilityInfoForTag(SelectedAbility.AbilityTag).TypeTag;
		//发送取消选等待装备技能广播
		StopWaitForEquipDelegate.Broadcast(SelectedAbilityType);
		bWaitingForEquipSelect = false;
	}
	
	//预定义能力状态标签
	FGameplayTag AbilityStatus;
	const FBaseGameplayTags GameplayTags = FBaseGameplayTags::Get();
	//获取当前玩家剩余技能点
	const int32 SpellPoints = GetBasePS()->GetSpellPoints();
	//判断能力标签为null
	const bool bTagValid = AbilityTag.IsValid();
	//判断能力标签是否为None
	const bool bTagNone = AbilityTag.MatchesTag(GameplayTags.Abilities_None);
	//获取能力规格
	const FGameplayAbilitySpec* AbilitySpec = GetBaseASC()->GetSpecFromAbilityTag(AbilityTag);
	//判断如果查找该能力是否已激活
	const bool bSpecValid = AbilitySpec != nullptr;
	//如果能力标签无效、能力标签为None、能力标签对应的技能未激活,技能为锁定
	if (!bTagValid || bTagNone || !bSpecValid)
	{
		AbilityStatus = GameplayTags.Abilities_Status_Locked;
	}
	else
	{
		//如果能力标签有效、能力标签不为None、能力标签对应的技能已激活,把能力状态设置能力规格中的能力状态
		AbilityStatus = GetBaseASC()->GetStatusFromSpec(*AbilitySpec);
	}
	//设置保存当前选择的技能
	SelectedAbility.AbilityTag = AbilityTag;
	SelectedAbility.StatusTag = AbilityStatus;
	//是否禁用升级技能按钮
	bool bEnableSpendPoints = false;
	//是否禁用装备技能按钮
	bool bEnableEquip = false;
	//调用判断
	ShouldEnableButtons(AbilityStatus, SpellPoints, bEnableSpendPoints, bEnableEquip);
	//当前技能描述
	FString Description;
	//下一级技能描述
	FString NextLevelDescription;
	//调用获取能力描述
	GetBaseASC()->GetDescriptionsByAbilityTag(AbilityTag,Description,NextLevelDescription);
	//广播按钮状态
	SpellSelectedDelegate.Broadcast(bEnableSpendPoints, bEnableEquip,Description, NextLevelDescription);
}
//取消选择技能
void USpellMenuWidgetController::CancelSpellSelection()
{
	if (bWaitingForEquipSelect)
	{
		//TODO：取消选择技能时 发送取消选择委托，这2行委托以后改成拖拽的可以去掉
		//能力类型
		const FGameplayTag SelectedAbilityType = AbilityInfo->FindAbilityInfoForTag(SelectedAbility.AbilityTag).TypeTag;
		//发送取消选等待装备技能广播
		StopWaitForEquipDelegate.Broadcast(SelectedAbilityType);
		bWaitingForEquipSelect = false;
	}
	
	//设置选择的能力标签为None
	SelectedAbility.AbilityTag = FBaseGameplayTags::Get().Abilities_None;
	//设置选择技能的状态为锁定
	SelectedAbility.StatusTag = FBaseGameplayTags::Get().Abilities_Status_Locked;
	//广播取消选择广播 全部为false 和 空字符串
	SpellSelectedDelegate.Broadcast(false, false,FString(), FString());

}

//升级技能按钮点击处理
void USpellMenuWidgetController::SpendPointButtonPressed()
{
	if (GetBaseASC())
	{
		//调用能力系统组件中的自定义服务器升级技能函数
		GetBaseASC()->ServerSpendSpellPoint(SelectedAbility.AbilityTag);
	}
}
//点击装备按钮时处理函数
void USpellMenuWidgetController::EquipButtonPressed()
{
	//从能力信息中获取对应能力的能力类型
	const FGameplayTag AbilityType = AbilityInfo->FindAbilityInfoForTag(SelectedAbility.AbilityTag).TypeTag;
	//设置等待装备技能选择变量
	bWaitingForEquipSelect = true;
	WaitForEquipDelegate.Broadcast(AbilityType);
	const FGameplayTag SelectedStatus = GetBaseASC()->GetStatusTagFromAbilityTag(SelectedAbility.AbilityTag);
	//判断状态是否是已装备
	if (SelectedStatus.MatchesTagExact(FBaseGameplayTags::Get().Abilities_Status_Equipped))
	{
		//把选择的插槽设置成选择的技能输入标签
		SelectedSlot = GetBaseASC()->GetSlotFromAbilityTag(SelectedAbility.AbilityTag);
	}
}
//法术插槽处理,这里是调用能力系统组件中 服务器操作处理能力按键插槽信息相关处理和广播的入口 （重点）
void USpellMenuWidgetController::SpellSlotPressed(const FGameplayTag& SlotTag, const FGameplayTag& AbilityType)
{
	//如果不是等待装备技能选择的状态就直接返回（未来改成拖动也要有一个判断正在拖动状态）
	if (!bWaitingForEquipSelect) return;
	//检查所选技能是否于槽位类型是否匹配，如果不匹配则不操作直接返回（未来这里会是 当鼠标松手时 触发的技能于槽位是否匹配）
	//获取选择的能力类型标签
	const FGameplayTag& SelectedAbilityType = AbilityInfo->FindAbilityInfoForTag(SelectedAbility.AbilityTag).TypeTag;
	//判断类型是否匹配，不匹配就返回
	if (!SelectedAbilityType.MatchesTagExact(AbilityType)) return;
	
	//将选择的技能分配到指定的槽位（这个要服务器处理）
	GetBaseASC()->ServerEquipAbility(SelectedAbility.AbilityTag,SlotTag);
}
//技能装备函数,能力标签、状态标签、按键输入插槽标签、上一个输入插槽标签
void USpellMenuWidgetController::OnAbilityEquipped(const FGameplayTag& AbilityTag, const FGameplayTag& Status, const FGameplayTag& Slot, const FGameplayTag& PreviousSlot)
{
	//设置不再等待装备技能
	bWaitingForEquipSelect = false;
	const FBaseGameplayTags GameplayTags = FBaseGameplayTags::Get();
	//创建上一个槽位技能数据体
	FBaseAbilityInfo LastSlotInfo;
	//设置能力状态已解锁
	LastSlotInfo.StatusTag = GameplayTags.Abilities_Status_Unlocked;
	LastSlotInfo.InputTag = PreviousSlot;
	LastSlotInfo.AbilityTag = GameplayTags.Abilities_None;
	//如果前一个槽位是有效槽位 ,则广播清除上一个槽位 用于清除这个标签内上一个技能的标签
	AbilityInfoDelegate.Broadcast(LastSlotInfo);
	
	//创建当前新槽位技能数据体
	FBaseAbilityInfo Info = AbilityInfo->FindAbilityInfoForTag(AbilityTag);
	Info.StatusTag = Status;
	Info.InputTag = Slot;
	//广播新装备技能信息
	AbilityInfoDelegate.Broadcast(Info);
	//停止播放等待选择框动画
	StopWaitForEquipDelegate.Broadcast(AbilityInfo->FindAbilityInfoForTag(AbilityTag).AbilityTag);
	//通知分配完成广播,用于取消 法术选择等效果（如果以后改成拖拽，可能没用 也可能作用于删除掉拖拽创建的一些界面东西吧）
	SpellReassigedDelegate.Broadcast(AbilityTag);
	//取消法术选择效果
	CancelSpellSelection();
}

//设置是否可升级技能按钮 和 是否可装备技能按钮
void USpellMenuWidgetController::ShouldEnableButtons(const FGameplayTag& AbilityStatus, int32 SpellPoints,
	bool& bShouldEnableSpellPointsButton, bool& bShouldEnableEquipButton)
{
	const FBaseGameplayTags GameplayTags = FBaseGameplayTags::Get();
	//设置确认升级按钮默认禁用
	bShouldEnableSpellPointsButton = false;
	//设置装备技能按钮默认禁用
	bShouldEnableEquipButton = false;
	//检查状态是否已装备
	if (AbilityStatus.MatchesTagExact(GameplayTags.Abilities_Status_Equipped))
	{
		//如果已装备说明可装备,返回true
		bShouldEnableEquipButton = true;
		//点数大于0说明可升级，返回true
		if (SpellPoints > 0)
		{
			bShouldEnableSpellPointsButton = true;
		}
	}
	//检查是否可解锁
	else if (AbilityStatus.MatchesTagExact(GameplayTags.Abilities_Status_Eligible))
	{
		if (SpellPoints > 0)
		{
			bShouldEnableSpellPointsButton = true;
		}
		
	}
	//检查是否已解锁
	else if (AbilityStatus.MatchesTagExact(GameplayTags.Abilities_Status_Unlocked))
	{
		//已解锁说明可装备，返回true
		bShouldEnableEquipButton = true;
		if (SpellPoints > 0)
		{
			bShouldEnableSpellPointsButton = true;
		}
	}
	//检查是否锁定 锁定任何按钮都不显示所以不需要判断
	// else if (AbilityStatus.MatchesTagExact(GameplayTags.Abilities_Status_Locked))
	// {
	// 	
	// }
}
